package com.example.project.projectspringcloud.service.impl.user;

import com.example.project.projectspringcloud.common.Constants;
import com.example.project.projectspringcloud.common.OperationException;
import com.example.project.projectspringcloud.dao.user.MenuMapper;
import com.example.project.projectspringcloud.dao.user.RelationRoleMenuMapper;
import com.example.project.projectspringcloud.dao.user.RoleMapper;
import com.example.project.projectspringcloud.entity.user.Menu;
import com.example.project.projectspringcloud.entity.user.RelationRoleMenu;
import com.example.project.projectspringcloud.entity.user.Role;
import com.example.project.projectspringcloud.service.user.PermissionService;
import com.example.project.projectspringcloud.utils.RedisUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
@Transactional(rollbackFor = Exception.class)
public class PermissionServiceImpl implements PermissionService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RelationRoleMenuMapper relationRoleMenuMapper;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public List<Role> roleList(Role role) {
        return roleMapper.selectAll(role);
    }

    @Override
    public Role getRole(Role role) {
        return roleMapper.selectByPrimaryKey(role.getId());
    }

    @Override
    public boolean saveRole(Role role) throws OperationException {
        if (role.isNewRecord()) {
            role.setCreateDate(new Date());
            return roleMapper.insert(role) > 0;
        } else {
            role.setUpdateDate(new Date());
            return roleMapper.updateByPrimaryKeySelective(role) > 0;
        }
    }

    @Override
    public boolean deleteRole(Integer[] idarr) {

        return roleMapper.deleteByArrayPrimaryKey(idarr) > 0;
    }

    @Override
    public List<Menu> menuList(Menu menu) {
        List<Menu> menus = menuMapper.selectAll(menu);
        List<Menu> parents = new ArrayList<>();
        parents.addAll(menus);
        setSubMenu(parents, menus);
        return parents;
    }

    @Override
    public Menu getMenu(Menu menu) {
        return menuMapper.selectByPrimaryKey(menu.getId());
    }

    @Override
    public boolean saveMenu(Menu menu) throws OperationException {
        if (menu.isNewRecord()) {
            menu.setCreateDate(new Date());
            menuMapper.insert(menu);
        } else {
            menu.setUpdateDate(new Date());
            menuMapper.updateByPrimaryKeySelective(menu);
        }
        selectAllMenuByRole(true);
        return true;
    }

    @Override
    public boolean deleteMenu(Integer[] idarr) {
        relationRoleMenuMapper.deleteByMenuId(idarr);
        return menuMapper.deleteByArrayPrimaryKey(idarr) > 0;
    }

    @Override
    public List<Integer> getMenuListByRoleId(Integer id) throws OperationException {

        return relationRoleMenuMapper.getMenuListByRoleId(id);
    }

    @Override
    public void updateRelationRoleMenu(Integer roleId, Integer[] menus) throws OperationException {
        relationRoleMenuMapper.deleteByRoleId(roleId);
        for (Integer i : menus) {
            relationRoleMenuMapper.insert(new RelationRoleMenu(roleId, i));
        }
    }

    @Override
    public List<Menu> selectAllMenuByRole(boolean constraint) {
        List<Menu> results = new ArrayList<>();
        // 获取当前用户角色
        if (SecurityContextHolder.getContext().getAuthentication() != null) {
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            Set<String> roleSet = new HashSet<>();
            if (!"anonymousUser".equals(principal)) {
                Iterator iterator = ((UserDetails) principal).getAuthorities().iterator();
                while (iterator.hasNext()) {
                    roleSet.add(iterator.next().toString());
                }
            }
            // 通过角色获取相应menu
            if (roleSet.size() != 0 || constraint) {
                if (redisUtil.hasKey(Constants.MENU_LIST_OF_ROLE_PREFIX + roleSet.toString()) && !constraint) {
                    return new Gson().fromJson((String) redisUtil.get(Constants.MENU_LIST_OF_ROLE_PREFIX + roleSet.toString()), new TypeToken<List<Menu>>() {
                    }.getType());
                } else {
                    List<Menu> menus = menuMapper.selectAllMenuByRole(roleSet);
                    List<Menu> parents = new ArrayList<>();
                    menus.forEach(t -> {
                        if (t.getParent() == null || t.getParent() == 0) {
                            parents.add(t);
                        }
                    });
                    setSubMenu(parents, menus);
                    redisUtil.set(Constants.MENU_LIST_OF_ROLE_PREFIX + roleSet.toString(), new Gson().toJson(parents), 600);
                    results = parents;
                }
            }
        }
        return results;
    }

    private void setSubMenu(List<Menu> parents, List<Menu> menus) {
        for (Menu menu : parents) {
            List<Menu> subs = new ArrayList<>();
            for (Menu sub : menus) {
                if (sub.getParent() != null && sub.getParent().equals(menu.getId())) {
                    subs.add(sub);
                }
            }
            menu.setSubList(subs);
            setSubMenu(menu.getSubList(), menus);
        }
    }
}
